package base

import "fmt"

type netNode struct {
	B            float64
	L            float64
	connectnodes Set
}

// Set 结构体
type Set map[string]struct{}

// 添加元素到 Set
func (s Set) Add(value string) {
	s[value] = struct{}{}
}

// 删除 Set 中的元素
func (s Set) Remove(value string) {
	delete(s, value)
}

// 检查元素是否在 Set 中
func (s Set) Contains(value string) bool {
	_, exists := s[value]
	return exists
}

// 获取 Set 的大小
func (s Set) Size() int {
	return len(s)
}

// 遍历 Set
func (s Set) Iterate() {
	for value := range s {
		fmt.Println(value)
	}
}

type netLine struct {
	LNodename string
	RNodename string
	isHadSet  bool
}
type ringNode struct {
	NodeName  string
	LNodename string
	RNodename string
}

type XyPoint struct {
	B    float64
	L    float64
	Name string
}

type AreasFromTriangles struct {
	triangles [][3]XyPoint
	nodeMap   map[string]netNode
	lines     []netLine
}

func (this *AreasFromTriangles) InitSetNetNodeAndLine() {
	if this.nodeMap == nil {
		this.nodeMap = make(map[string]netNode)
	}
	if this.lines == nil {
		this.lines = make([]netLine, 0)
	}

	for _, tri := range this.triangles {
		for i := 0; i < 3; i++ {
			//节点设置
			_, exists := this.nodeMap[tri[i].Name]
			var set Set
			if exists {
				set = this.nodeMap[tri[i].Name].connectnodes
				delete(this.nodeMap, tri[i].Name)
			} else {
				set = make(Set)
			}
			set.Add(tri[(i+1)%3].Name)
			set.Add(tri[(i+2)%3].Name)
			this.nodeMap[tri[i].Name] = netNode{B: tri[i].B, L: tri[i].L, connectnodes: set}

			//基线设置
			isExists := false
			for _, oneLine := range this.lines {
				if (oneLine.LNodename == tri[i].Name && oneLine.RNodename == tri[(i+2)%3].Name) || (oneLine.RNodename == tri[i].Name && oneLine.LNodename == tri[(i+2)%3].Name) {
					//基线已经记录到了
					isExists = true
					break
				}
			}
			if !isExists {
				this.lines = append(this.lines, netLine{LNodename: tri[i].Name, RNodename: tri[(i+2)%3].Name})
			}
		}
	}
}

// @Summary 获取用户列表
// @Description 获取环上的点
// @Tags 胡恒斌
// @Accept  json
// @Produce  json
// @Success 200 {array} string
func (this *AreasFromTriangles) GetRings() (rval [][]XyPoint) {
	rval = make([][]XyPoint, 0)
	this.InitSetNetNodeAndLine()
	allRing := this.generateRings(make([]ringNode, 0), "", this.getBorders())
	var maxRing []ringNode
	var maxRingIndex int
	for index, one := range allRing {
		if len(maxRing) < len(one) {
			maxRing = one
			maxRingIndex = index
		}
	}
	rval0 := make([]XyPoint, 0)
	for _, one := range maxRing {
		rval0 = append(rval0, XyPoint{Name: one.NodeName, B: this.nodeMap[one.NodeName].B, L: this.nodeMap[one.NodeName].L})
	}
	rval = append(rval, rval0)
	for index, oneRing := range allRing {
		if index == maxRingIndex {
			continue
		}
		rval0 := make([]XyPoint, 0)
		for _, one := range oneRing {
			rval0 = append(rval0, XyPoint{Name: one.NodeName, B: this.nodeMap[one.NodeName].B, L: this.nodeMap[one.NodeName].L})
		}
		rval = append(rval, rval0)
	}
	return rval
}

func (this *AreasFromTriangles) getBorders() (boders []netLine) {
	for _, oneLine := range this.lines {
		i := 0
		for one := range this.nodeMap[oneLine.LNodename].connectnodes {
			for two := range this.nodeMap[oneLine.RNodename].connectnodes {
				if one == two {
					i++
				}
			}
		}
		if i == 1 {
			boders = append(boders, oneLine)
		}
	}
	return
}

func (this *AreasFromTriangles) generateRings(ring []ringNode, beginPoint string, borders []netLine) [][]ringNode {
	//确定环的起始点
	var nextPoints []string
	if beginPoint == "" {
		for _, one := range borders {
			if !one.isHadSet && len(findNetLinesAnotherRPWithLP(one.RNodename, borders)) == 2 {
				beginPoint = one.LNodename
				break
			}
		}
	}
	lastNodeName := ""
	nowNodeName := beginPoint
	rings := make([][]ringNode, 0)
	isClose := false
	nextPoints = findNetLinesAnotherRPWithLP(nowNodeName, borders)
	for !isClose {
		switch len(nextPoints) {
		case 0:
			return rings
		case 1:
			if nextPoints[0] == ring[0].NodeName {
				ring[0].LNodename = nowNodeName
				setBorderHadSet(nowNodeName, nextPoints[0], borders)
				ring = append(ring, ringNode{NodeName: nowNodeName, RNodename: nextPoints[0], LNodename: lastNodeName})
				isClose = true
				continue
			}
			ring = append(ring, ringNode{NodeName: nowNodeName, RNodename: nextPoints[0], LNodename: lastNodeName})
			setBorderHadSet(nowNodeName, nextPoints[0], borders)
			lastNodeName = nowNodeName
			nowNodeName = nextPoints[0]
		case 2:
			ring = append(ring, ringNode{NodeName: nowNodeName, RNodename: nextPoints[0], LNodename: lastNodeName})
			setBorderHadSet(nowNodeName, nextPoints[0], borders)
			lastNodeName = nowNodeName
			nowNodeName = nextPoints[0]
		default:
			for _, p := range nextPoints {
				borders2 := copyBorders(borders)
				setBorderHadSet(p, nowNodeName, borders2)
				sub_rings := this.generateRings([]ringNode{{NodeName: nowNodeName, RNodename: p}}, p, borders2)
				for _, oneRing := range sub_rings {
					rings = append(rings, oneRing)
					for _, oneNode := range oneRing {
						setBorderHadSet(oneNode.RNodename, oneNode.NodeName, borders)
					}
				}
			}
		}
		nextPoints = findNetLinesAnotherRPWithLP(nowNodeName, borders)
	}

	rings = append(rings, ring)
	// for _, one := range borders {
	// 	if !one.isHadSet {
	// 		fmt.Println(one.LNodename, one.RNodename)
	// 	}
	// }
	for _, one := range borders {
		if !one.isHadSet {
			rings = append(rings, this.generateRings(make([]ringNode, 0), "", borders)...)
			break
		}
	}
	return rings
}

func copyBorders(borders []netLine) []netLine {
	rval := make([]netLine, 0)
	for _, one := range borders {
		rval = append(rval, netLine{LNodename: one.LNodename, RNodename: one.RNodename, isHadSet: one.isHadSet})
	}
	return rval
}
func findNetLinesAnotherRPWithLP(pointName string, netLines []netLine) (rval []string) {
	for _, one := range netLines {
		if !one.isHadSet && one.LNodename == pointName {
			rval = append(rval, one.RNodename)
		} else if !one.isHadSet && one.RNodename == pointName {
			rval = append(rval, one.LNodename)
		}
	}
	return
}

func setBorderHadSet(Lname string, Rname string, borders []netLine) {
	for i, one := range borders {
		if (one.LNodename == Lname && one.RNodename == Rname) || (one.LNodename == Rname && one.RNodename == Lname) {
			borders[i].isHadSet = true
			return
		}
	}
	panic("严重错误，不存在这样的基线")
}

func NewAreasFromTriangles(points ...[3]XyPoint) AreasFromTriangles {
	rval := make([][3]XyPoint, 0)
	rval = append(rval, points...)
	return AreasFromTriangles{triangles: rval}
}
